package com.xbongbong.paas.help.base;

import com.alibaba.fastjson.JSON;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.ComboTypeEnum;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.field.LinkConditionPoJo;
import com.xbongbong.paas.field.LinkInfoPojo;
import com.xbongbong.paas.pojo.dto.LinkConditionDataDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.parent.condition.ConditionFieldHandler;
import com.xbongbong.parent.condition.ConditionFieldHandlerFactory;
import com.xbongbong.parent.condition.ProConditionHelp;
import com.xbongbong.pro.enums.businessrule.enums.RuleValueTypeEnum;
import com.xbongbong.saas.constant.StringConstant;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author 吴峰
 * @version v1.0
 * @date 2019/6/2 13:05
 * @since v1.0
 */
@Component
public class BaseLinkBoolQueryBuilderService {

    @Resource
    private ConditionFieldHandlerFactory conditionFieldHandlerFactory;
    @Resource
    private ProConditionHelp proConditionHelp;

    public Map<String, Object> getValueMap(Map<String, FieldAttrEntity> explainMap, List<LinkConditionDataDTO> value, LinkInfoPojo linkInfoPojo, String corpid) throws XbbException {
        if (value == null) {
            return new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        }
        Map<String, Object> valueMap = new HashMap<>(value.size());
        for (LinkConditionDataDTO item : value) {
            if (Objects.isNull(item.getValue()) || StringUtil.isEmpty(item.getValue().toString())) {
                continue;
            }
            if (Objects.nonNull(item.getValueType()) && Objects.equals(item.getValueType(), RuleValueTypeEnum.FIXED_VALUE.getType())) {
                continue;
            }
            if (explainMap.containsKey(item.getAttr()) && !item.getAttr().contains(StringConstant.POINT)) {
                // 非子表单
                FieldAttrEntity fieldAttrEntity = explainMap.get(item.getAttr());
                if (Objects.isNull(fieldAttrEntity)) {
                    continue;
                }
                valueMap.putAll(getValue(fieldAttrEntity, item));
            } else if (item.getAttr().contains(StringConstant.POINT)) {
                // 子表单
                String[] attr = item.getAttr().split("\\.");
                FieldAttrEntity fieldAttrEntity = explainMap.get(attr[0]);
                Map<String, FieldAttrEntity> subExplainMap = ExplainUtil.getExplainMap(JSON.toJSONString(fieldAttrEntity.getSubForm().getItems()), null);
                FieldAttrEntity subField = subExplainMap.get(attr[1]);
                if (Objects.isNull(subField)) {
                    continue;
                }
                Map<String, Object> subValueMap = getValue(subField, item);
                valueMap.putAll(subValueMap);
            }
        }
        return valueMap;
    }

    private Map<String, Object> getValue(FieldAttrEntity fieldAttrEntity, LinkConditionDataDTO item) {
        Map<String, Object> valueMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        FieldTypeEnum fieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(fieldAttrEntity.getFieldType());
        switch (fieldTypeEnum) {
            case COMBO:
            case RADIO_GROUP:
                if (Objects.equals(ComboTypeEnum.CUSTOM.getType(), fieldAttrEntity.getComboType())) {
                    Object itemValue = item.getValue();
                    if (item.getValue() instanceof Map ){
                        Map<String, Object> itemValueMap = (Map) itemValue;
                        itemValue = itemValueMap.get("text");
                        valueMap.put(item.getAttr(), itemValue);
                    } else {
                        // 从item里获取text，并放到容器中，将用于后续从目标表单对比text，拿出目标表单的value
                        List<ItemPoJo> itemPoJoList = fieldAttrEntity.getItems();
                        Map<Object, ItemPoJo> itemMap = new HashMap<>(itemPoJoList.size());
                        for (ItemPoJo itemPoJo : itemPoJoList) {
                            itemMap.put(itemPoJo.getValue(), itemPoJo);
                        }
                        if (itemMap.containsKey(item.getValue())) {
                            valueMap.put(item.getAttr(), itemMap.get(item.getValue()).getText());
                        }
                    }
                }else {
                    Map<String, Object> itemValueMap = (Map) item.getValue();
                    Object itemValue = itemValueMap.get("text");
                    valueMap.put(item.getAttr(), itemValue);
                }
                break;
            case COMBO_CHECK:
            case CHECKBOX_GROUP:
                List<ItemPoJo> itemList = fieldAttrEntity.getItems();
                Map<Object, Object> itemMap = new HashMap<>(itemList.size());
                itemList.forEach(itemValue->{
                    itemMap.put(itemValue.getText(), itemValue.getValue());
                });
                List<Object> valueList = new ArrayList<>();
                List<Map<String, Object>> jsonArray = (ArrayList) item.getValue();
                for (Map jsonObject: jsonArray) {
                    valueList.add(jsonObject.get("text"));
                }
                valueMap.put(item.getAttr(), valueList);
                break;
            default:
                valueMap.put(item.getAttr(), item.getValue());
                break;
        }
        return valueMap;
    }

    /**
     * 拼装搜索条件的数据
     * @param relyExplainMap
     * @param valueMap
     * @param condition
     * @param boolQueryBuilder
     * @return false 条件不满足不能去查es； true：条件满足可以去查es
     */
    public Boolean returnBoolQueryBuilder(Map<String, FieldAttrEntity> relyExplainMap, Map<String, FieldAttrEntity> explainMap, Map<String, Object> valueMap,
                                                         List<LinkConditionPoJo> condition, BoolQueryBuilder boolQueryBuilder, LinkInfoPojo linkInfoPojo, String corpid) throws XbbException {
        // 拼接查找条件
        if (Objects.nonNull(condition) && !condition.isEmpty()) {
            for (LinkConditionPoJo item : condition) {
                // 联动字段包含联动条件中设置的字段
                if (relyExplainMap.containsKey(item.getRely())) {
                    // 获取联动条件的比较字段
                    FieldAttrEntity relyFieldAttrEntity = relyExplainMap.get(item.getRely());

                    // 设置条件(注：关联表单不能选择子表单字段，所以不必处理子表单)
                    Object object;
                    Integer relyFieldType = relyFieldAttrEntity.getFieldType();
                    if (Objects.nonNull(item.getValueType()) && Objects.equals(item.getValueType(), RuleValueTypeEnum.FIXED_VALUE.getType())) {
                        // 固定值
                        object = item.getValue();
                        ConditionFieldHandler conditionFieldHandler = conditionFieldHandlerFactory.getRelyFormFixedValueByFieldType(relyFieldType);
                        object = conditionFieldHandler.handlerLinkDataFixedValue(corpid, relyFieldAttrEntity, linkInfoPojo, object);
                        dealWithConditions(object, boolQueryBuilder, corpid, item, linkInfoPojo.getLinkSaasMark(), linkInfoPojo.getLinkBusinessType(), relyFieldType);
                    } else {
                        FieldAttrEntity fieldAttrEntity = proConditionHelp.getFieldByConditionAttr(item.getAttr(), explainMap);
                        Object equalValue = valueMap.get(item.getAttr());
                        if (proConditionHelp.isEmpty(equalValue, fieldAttrEntity.getFieldType())) {
                            if (Objects.nonNull(item.getValueType())) {
                                if (Objects.equals(ConditionEnum.NOEQUAL.getSymbol(), item.getSymbol())) {
                                    EsUtil.nonNull(relyFieldAttrEntity.getFieldType(), boolQueryBuilder, item.getRely());
                                } else {
                                    EsUtil.isNull(relyFieldAttrEntity.getFieldType(), boolQueryBuilder, item.getRely());
                                }
                            } else {
                                EsUtil.isNull(relyFieldAttrEntity.getFieldType(), boolQueryBuilder, item.getRely());
                            }
                        } else {
                            LinkInfoPojo thisLinkInfoPojo = fieldAttrEntity.getLinkInfo();
                            // 校验关联数据或者系统关联业务是否关联同一业务或者同一表单
                            proConditionHelp.validateTheForm(fieldAttrEntity, relyFieldAttrEntity, linkInfoPojo.getLinkBusinessType());
                            if (ProConditionHelp.validateIsLinkData(fieldAttrEntity.getFieldType(), relyFieldAttrEntity.getFieldType())) {
                                Map<String, Object> attrMap = (Map<String, Object>) valueMap.get(item.getAttr());
                                Map<String, Object> dataMap = (Map<String, Object>) attrMap.get(StringConstant.JSON_DATA);
                                if (dataMap == null) {
                                    continue;
                                }
                                // 获取关联数据的主键，然后去拿对应的数据
                                valueMap.put(item.getAttr(), dataMap.get(thisLinkInfoPojo.getLinkKey()));
                            }
                            equalValue = valueMap.get(item.getAttr());
                            // 设置条件
                            if (Objects.nonNull(item.getValueType())) {
                                // 动态值
                                ConditionFieldHandler conditionFieldHandler = conditionFieldHandlerFactory.getHandlerRelyFormByFieldType(relyFieldType);
                                object = conditionFieldHandler.handlerRelyFormField(corpid, fieldAttrEntity, relyFieldAttrEntity, item, linkInfoPojo, equalValue);
                                dealWithConditions(object, boolQueryBuilder, corpid, item, linkInfoPojo.getLinkSaasMark(), linkInfoPojo.getLinkBusinessType(), relyFieldType);
                            } else {
                                // 设置需要相等的条件
                                proConditionHelp.needEqual(equalValue, boolQueryBuilder, linkInfoPojo.getLinkFormId(), linkInfoPojo.getLinkSaasMark(), linkInfoPojo.getLinkBusinessType(),
                                        relyFieldAttrEntity, fieldAttrEntity, corpid);
                            }
                        }
                    }
                }
            }
        }
        return true;
    }

    /**
     * 拼接查询条件
     * @param value
     * @param boolQueryBuilder
     * @param corpid
     * @param linkCondition
     * @param businessType
     * @param relyFieldType
     * @return
     * @author xingxing.xiao
     * @date 2020/07/28 16:54
     */
    private void dealWithConditions (Object value, BoolQueryBuilder boolQueryBuilder, String corpid, LinkConditionPoJo linkCondition, Integer saasMark, Integer businessType, Integer relyFieldType) throws XbbException {

        List<ConditionsEntityExt> conditionList = new ArrayList<>();
        ConditionsEntityExt conditionsEntityExt = new ConditionsEntityExt(linkCondition.getRely(), "", relyFieldType, linkCondition.getSymbol());
        // 处理值
        if (value instanceof List) {
            List<Object> list = JSON.parseArray(JSON.toJSONString(value), Object.class);
            conditionsEntityExt.setValue(list);
        } else if (Objects.equals(FieldTypeEnum.DATAID.getAlias(), linkCondition.getRely()) && Objects.nonNull(value)) {
            conditionsEntityExt.setValue(Arrays.asList(value));
        } else {
            List<Object> list = new ArrayList<>();
            list.add(value);
            conditionsEntityExt.setValue(list);
        }
        conditionList.add(conditionsEntityExt);
        // 地址查询条件封装
        List<List<ConditionsEntityExt>> shouldConditions = new ArrayList<>();
        EsUtil.addressSearchCondition(conditionList, shouldConditions);
        // 地址查询条件封装
        EsUtil.parseShouldCondition(boolQueryBuilder, shouldConditions, "", corpid, businessType);
        EsUtil.parseCondition(boolQueryBuilder, conditionList, "", corpid, businessType);
    }

}
